import { onMounted, type Ref, ref } from 'vue';

interface HookOptions<P = any, D = any> {
  /**
   * 是否自动请求，为true时，将在onMounted钩子自动执行一次getData
   */
  auto?: boolean;

  loading?: Ref<boolean>;

  params?: P;

  success?: (res: D | undefined) => void;
}

/**
 * 默认参数
 */
const defaultOptions: HookOptions = {
  auto: false
};

type FunctionParams<T> = T extends (arg: infer P) => any ? P : never;

type ApiResult<T extends PromiseFn> = PromiseValue<ReturnType<T>>;

type SuccessCallbackFunction<F extends PromiseFn> = (
  res: PromiseValue<ReturnType<F>>
) => void;

export default function useRequest<
  API extends PromiseFn,
  D extends FunctionParams<API>
>(api: API, options?: HookOptions<D, ApiResult<API>>) {
  options = { ...defaultOptions, ...options };

  const successFunctions: ((res: SuccessCallbackFunction<API>) => void)[] = [];
  const loading = ref(false);
  const data = ref<PromiseValue<ReturnType<API>>>();

  // 切换loading状态
  function toggleLoading(flag: boolean) {
    loading.value = flag;
    // 如果设置了自定义loading属性，则一起切换
    if (options?.loading !== undefined) {
      options.loading.value = flag;
    }
  }

  // 获取数据
  async function request(params?: Partial<FunctionParams<API>>) {
    toggleLoading(true);
    try {
      data.value = await api({
        ...options?.params,
        ...params
      });
      if (options?.success) {
        options.success(data.value);
      }
      successFunctions.forEach((fn) => fn(data.value!));
      return data.value!;
    } catch (err) {
      toggleLoading(false);
      throw err;
    } finally {
      toggleLoading(false);
    }
  }

  function onSuccess(fn: SuccessCallbackFunction<API>) {
    successFunctions.push(fn as any);
  }

  onMounted(() => {
    if (options?.auto) {
      request();
    }
  });

  return {
    loading,
    data,
    request,
    onSuccess
  };
}
